import { ESVOptionUeUri, ESVOptionUe, ESVOptionUeWs } from "earthsdk2s";
import { createProcessingFromAsyncFunc, Destroyable, Event } from "xbsj-base";
import { UeCloudViewer } from "../CustomPixelStream/UeCloudViewer";
import { ESUeViewer } from "../index";
import { UeLocalViewer } from "./UeLocalViewer";
import { ViewerInstance } from "./ViewerInstance";
import { ViewerLocalInstance } from "./ViewerLocalInstance";
export class ViewerCreating extends Destroyable {
    private _reconnectEvent = this.dv(new Event());

    constructor(container: HTMLDivElement, params: ESVOptionUe, ueViewer: ESUeViewer) {
        super();
        const hasPorp = (obj: Object, str: string) => { return obj.hasOwnProperty(str); }

        //重连时间间隔
        let intervalTime = 3000;
        //定时器
        let timer: number;
        this.d(() => { timer && clearTimeout(timer) })

        // @ts-ignore 
        // if (window.ue && window.ue.es) {
        if (window.ue) {//大屏模式
            ueViewer.setStaus('Creating');
            ueViewer.setStatusLog(`开始创建本地视口...`);
            const viewer = this.dv(new UeLocalViewer(container, ueViewer));
            this.d(() => ueViewer.viewer = undefined);
            ueViewer.viewer = viewer;
            ueViewer.setStaus('Created');
            ueViewer.setStatusLog('本地视口创建成功!');
            this.dv(new ViewerLocalInstance(ueViewer, viewer));
        } else if (hasPorp(params.options, 'ws') || (hasPorp(params.options, 'uri') && hasPorp(params.options, 'app'))) {
            ueViewer.setStaus('Creating');
            ueViewer.setStatusLog(`开始创建云渲染视口...`);
            //为了重连时清空容器
            let videoContainer: HTMLDivElement | undefined;
            this.d(() => {
                ueViewer.setStaus('Raw');
                ueViewer.setStatusLog('');
                (container && videoContainer) && container.removeChild(videoContainer) && (videoContainer = undefined);
            });

            const createViewerProcessing = this.dv(createProcessingFromAsyncFunc<void, [subContainer: HTMLDivElement]>(async (cancelsManager, subContainer) => {
                videoContainer = document.createElement('div');
                videoContainer.setAttribute('earthsdk2-ue', 'earthsdk2-ue-videoContainer');
                videoContainer.style.cssText = `position:relative; height: 100%;width:100%;`;
                subContainer.appendChild(videoContainer);
                let wsserver, wsesmsg;
                if (hasPorp(params.options, 'ws')) {
                    const { ws, esmsg } = (params as ESVOptionUeWs).options;
                    wsserver = ws;
                    wsesmsg = esmsg;
                }
                if (hasPorp(params.options, 'uri') && hasPorp(params.options, 'app')) {
                    const { offsetWidth, offsetHeight } = videoContainer;
                    const { uri, app, token } = (params as ESVOptionUeUri).options;
                    const tokenStr = token ? `?essstoken=${token}` : '';
                    const resParam = `/${app}/${offsetWidth ?? 1920}/${offsetHeight ?? 1080}` + tokenStr;
                    console.log(`请求信令服务器: ${uri}instance${resParam}`);
                    const response = await cancelsManager.promise(fetch(`${uri}instance${resParam}`, { method: "GET", }));
                    const resultJson = await cancelsManager.promise(response.json());
                    if (resultJson && resultJson.status !== "ok") {
                        console.log(`信令服务器请求失败! ${JSON.stringify(resultJson, undefined, '    ')}`);
                        ueViewer.setStaus('Error');
                        ueViewer.setStatusLog(`信令服务器请求失败 ${JSON.stringify(resultJson, undefined, '    ')}`);
                        return;
                    }
                    const { server, esmsg } = resultJson;
                    wsserver = server;
                    wsesmsg = esmsg;
                    console.log(`信令服务器请求成功! ${JSON.stringify(resultJson, undefined, '    ')}`);
                }

                const viewer = this.dv(new UeCloudViewer(videoContainer, wsserver, wsesmsg, ueViewer));
                this.d(() => ueViewer.viewer = undefined);

                this.d(viewer.readyEvent.don(() => {
                    ueViewer.setStaus('Created');
                    ueViewer.setStatusLog('云渲染视口创建成功!');
                }));
                this.d(viewer.closeEvent.don((str) => {
                    ueViewer.setStaus('Error');
                    ueViewer.setStatusLog(`[${str}] 像素流连接中断或消息通信连接关闭!`);
                    this._reconnectEvent.emit();
                }));
                this.d(viewer.errorEvent.don((str) => {
                    ueViewer.setStaus('Error');
                    ueViewer.setStatusLog(`[${str}] 像素流连接错误或消息通信连接错误!`);
                    this._reconnectEvent.emit();
                }));

                await cancelsManager.promise(new Promise<void>(resolve => this.d(viewer.readyEvent.donce(resolve))));
                //连接成功时间间隔归零
                intervalTime = 1000;

                ueViewer.viewer = viewer;
                this.dv(new ViewerInstance(ueViewer, viewer));
            }));

            createViewerProcessing.start(container);

            this.d(this._reconnectEvent.don(() => {
                ueViewer.viewer && (!ueViewer.viewer.isDestroyed()) && ueViewer.viewer.destroy();
                ueViewer.viewer = undefined;
                videoContainer && container.removeChild(videoContainer) && (videoContainer = undefined);
                if (ueViewer.autoReconnect ?? true) {
                    ueViewer.setStaus('Reconnecting');
                    ueViewer.setStatusLog(`正在尝试重新连接...`);
                    timer = window.setTimeout(() => {
                        console.warn(`间隔：${intervalTime}ms,正在尝试重新连接...`);
                        createViewerProcessing.restart(undefined, container);
                    }, intervalTime);
                    intervalTime = (intervalTime * 2) > 30000 ? 30000 : (intervalTime * 2);
                }
            }))

            this.d(createViewerProcessing.errorEvent.don(error => {
                ueViewer.setStaus('Error');
                ueViewer.setStatusLog(`云渲染视口创建失败！`);
                this._reconnectEvent.emit();
            }));

        } else {
            ueViewer.setStaus('Error');
            ueViewer.setStatusLog(`视口创建失败！`);
            console.warn(`视口创建失败: option的uri或者app不存在，window.ue和window.ue.es也不存在，ws和esmsg地址也不存在`);
        }
    }
}
